package com.googlecode.mycontainer.maven.plugin;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DependencyResolutionRequiredException;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactCollector;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.dependency.tree.DependencyNode;
import org.apache.maven.shared.dependency.tree.DependencyTreeBuilder;
import org.apache.maven.shared.dependency.tree.DependencyTreeBuilderException;
/**
* @goal start
* @aggregator
*/
public class MycontainerStartMojo extends AbstractMojo {
/**
* The Maven project.
*
* @parameter expression="${project}"
* @required
* @readonly
*/
private MavenProject project;
/**
* The artifact repository to use.
*
* @parameter expression="${localRepository}"
* @required
* @readonly
*/
private ArtifactRepository localRepository;
/**
* The artifact factory to use.
*
* @component
* @required
* @readonly
*/
private ArtifactFactory artifactFactory;
/**
* The artifact metadata source to use.
*
* @component
* @required
* @readonly
*/
private ArtifactMetadataSource artifactMetadataSource;
/**
* The artifact collector to use.
*
* @component
* @required
* @readonly
*/
private ArtifactCollector artifactCollector;
/**
* The dependency tree builder to use.
*
* @component
* @required
* @readonly
*/
private DependencyTreeBuilder dependencyTreeBuilder;
/**
* @parameter
*/
private Set<String> packs;
/**
* @parameter expression="${mycontainer.debug2info}" default-value="false"
* @required
*/
private boolean debug2info;
/**
* @parameter expression="${mycontainer.start.resolveConflict}"
* default-value="false"
* @required
*/
private boolean resolveConflict;
/**
* @parameter expression="${mycontainer.start.includeTests}"
* expression="false"
* @required
*/
private boolean includeTests = false;
/**
* @parameter expression="${basedir}/src/mycontainer/mycontainer-start.bsh"
*/
private File script;
/**
* Map of of plugin artifacts.
*
* @parameter expression="${plugin.artifactMap}"
* @required
* @readonly
*/
private Map<String, Artifact> pluginArtifactMap;
public MycontainerStartMojo() {
this.packs = new TreeSet<String>(Arrays.asList("jar", "ejb", "war"));
}
public void execute() throws MojoExecutionException, MojoFailureException {
if (!script.exists()) {
throw new MojoExecutionException("Beanshell not found: " + script);
}
Set<Artifact> artifacts = new HashSet<Artifact>();
Set<MavenProject> projects = new HashSet<MavenProject>();
resolveDependencies(artifacts, projects);
resolvePluginDependencies(artifacts);
if (resolveConflict) {
resolveConflicts(artifacts);
}
List<File> classpath = getProjectsClasspath(projects);
classpath.addAll(getArtifactsClasspath(artifacts));
exec(classpath);
}
private void resolveConflicts(Set<Artifact> artifacts) {
Map<String, Artifact> ret = new HashMap<String, Artifact>();
for (Artifact artifact : artifacts) {
String id = new StringBuilder().append(artifact.getGroupId()).append(':').append(artifact.getArtifactId()).append(':').append(artifact.getType()).toString();
Artifact old = ret.get(id);
if (old != null) {
debug("Conflict removed: " + artifact + " (" + old + ")");
} else {
ret.put(id, artifact);
}
}
}
private void resolvePluginDependencies(Set<Artifact> artifacts) {
getLog().info("Getting plugin dependencies...");
Collection<Artifact> coll = pluginArtifactMap.values();
for (Artifact artifact : coll) {
debug("Plugin dependency: " + artifact);
if (artifacts.add(artifact)) {
debug("Plugin dependency: " + artifact);
}
}
}
@SuppressWarnings("unchecked")
private void resolveDependencies(Set<Artifact> artifacts, Set<MavenProject> projects) throws MojoExecutionException {
if (packs.contains(project.getPackaging())) {
projects.add(project);
mountClasspath(project, artifacts);
}
List<MavenProject> collectedProjects = project.getCollectedProjects();
for (MavenProject module : collectedProjects) {
if (packs.contains(module.getPackaging())) {
projects.add(module);
mountClasspath(module, artifacts);
}
}
removeProjects(projects, artifacts);
}
private void exec(List<File> classpath) throws MojoExecutionException {
try {
List<URL> urls = new ArrayList<URL>(classpath.size());
for (File file : classpath) {
if (!file.exists()) {
getLog().warn("File not found to isolated classloader: " + file);
} else {
URL url = file.toURI().toURL();
debug("Classpath: " + url);
urls.add(url);
}
}
getLog().info("Creating classloader for: " + urls);
ClassLoader loader = URLClassLoader.newInstance(urls.toArray(new URL[urls.size()]));
MycontainerRunner runner = new MycontainerRunner(getLog(), loader, script);
runner.start();
runner.join();
} catch (MalformedURLException e) {
throw new MojoExecutionException("error", e);
} catch (InterruptedException e) {
throw new MojoExecutionException("error", e);
}
}
@SuppressWarnings("unchecked")
private List<File> getProjectsClasspath(Set<MavenProject> projects) throws MojoExecutionException {
try {
getLog().info("Including project classpath. includingTests: " + includeTests);
List<File> ret = new ArrayList<File>(projects.size());
for (MavenProject module : projects) {
List<String> elements = module.getCompileClasspathElements();
for (String element : elements) {
debug("Path: " + element);
ret.add(new File(element));
}
if (includeTests) {
elements = module.getTestClasspathElements();
for (String element : elements) {
debug("Path: " + element);
ret.add(new File(element));
}
}
}
return ret;
} catch (DependencyResolutionRequiredException e) {
throw new MojoExecutionException("error", e);
}
}
private List<File> getArtifactsClasspath(Collection<Artifact> artifacts) {
List<File> ret = new ArrayList<File>(artifacts.size());
for (Artifact artifact : artifacts) {
String path = localRepository.getBasedir() + "/" + localRepository.pathOf(artifact);
ret.add(new File(path));
}
return ret;
}
private void removeProjects(Set<MavenProject> projects, Set<Artifact> artifacts) {
for (MavenProject module : projects) {
Artifact artifact = module.getArtifact();
if (artifacts.remove(artifact)) {
debug("project removed: " + artifact);
}
}
}
@SuppressWarnings("unchecked")
private void mountClasspath(MavenProject module, Set<Artifact> artifacts) throws MojoExecutionException {
try {
Artifact artifact = module.getArtifact();
getLog().info("Mounting classpath: " + artifact);
artifacts.add(artifact);
DependencyNode root = dependencyTreeBuilder.buildDependencyTree(module, localRepository, artifactFactory, artifactMetadataSource, null, artifactCollector);
Iterator<DependencyNode> it = root.iterator();
while (it.hasNext()) {
DependencyNode node = it.next();
Artifact dependency = node.getArtifact();
String dependencyScope = dependency.getScope();
if ((Artifact.SCOPE_COMPILE.equals(dependencyScope) || (includeTests && Artifact.SCOPE_TEST.equals(dependencyScope))) && packs.contains(dependency.getType())) {
boolean add = artifacts.add(dependency);
if (add) {
debug("Dependency: " + dependencyScope + " " + dependency);
}
}
}
} catch (DependencyTreeBuilderException e) {
throw new MojoExecutionException("error", e);
}
}
private void debug(String msg) {
if (debug2info) {
getLog().info(msg);
} else {
getLog().debug(msg);
}
}
}